package cn.turboinfo.fuyang.api.provider.common.service.impl.wechat;

import cn.turboinfo.fuyang.api.domain.common.service.wechat.WechatPayService;
import cn.turboinfo.fuyang.api.domain.util.DateTimeFormatHelper;
import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReceiver;
import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingRequest;
import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingResult;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.ProfitSharingV3Service;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;

import static cn.turboinfo.fuyang.api.entity.common.constant.CurrencyConstant.CURRENCY_CNY;


@RequiredArgsConstructor
@Service
@Slf4j
public class CommonWechatPayServiceImpl implements WechatPayService {

    @Value("${kit.wechat.pay.appId:}")
    private String appId;

    @Value("${kit.wechat.pay.merchantId:}")
    private String merchantId;

    @Value("${kit.wechat.pay.pay-callback-url:}")
    private String payCallbackUrl;

    @Value("${kit.wechat.pay.refund-callback-url:}")
    private String refundCallbackUrl;

    private final WxPayService wxPayService;

    @Override
    public String generatePrepayment(String productName, Long payOrderId, Long amount, String payerOpenId, String attach) {
        // 查询是否存在支付订单
        WxPayOrderQueryV3Result orderQueryResult = findByPayOrderId(payOrderId);
        if (orderQueryResult != null) {
            // 如果存在支付订单，则取消支付订单
            cancelTransaction(payOrderId);
        }

        WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
        WxPayUnifiedOrderV3Request.Amount wxAmount = new WxPayUnifiedOrderV3Request.Amount();
        wxAmount.setTotal(Integer.parseInt(amount.toString()));
        request.setAmount(wxAmount);
        request.setAppid(appId);
        request.setMchid(merchantId);
        request.setDescription(productName);
        request.setNotifyUrl(payCallbackUrl);
        request.setOutTradeNo(payOrderId.toString());
        request.setAttach(attach);
        // 支付超时时间 写死30分钟
        request.setTimeExpire(ZonedDateTime.now().plusMinutes(30L).format(DateTimeFormatHelper.wechatDataTime));
        // 支付者信息
        WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
        payer.setOpenid(payerOpenId);
        request.setPayer(payer);
        WxPayUnifiedOrderV3Request.SettleInfo settleInfo = new WxPayUnifiedOrderV3Request.SettleInfo();
        settleInfo.setProfitSharing(true);
        request.setSettleInfo(settleInfo);

        // 调用下单方法，得到应答
        try {
            WxPayUnifiedOrderV3Result result = wxPayService.unifiedOrderV3(TradeTypeEnum.JSAPI, request);
            return result.getPrepayId();
        } catch (WxPayException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public WxPayOrderQueryV3Result findByPayOrderId(Long orderId) {
        WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request();
        request.setMchid(merchantId);
        request.setOutTradeNo(orderId.toString());
        try {
            return wxPayService.queryOrderV3(request);
        } catch (WxPayException e) {
            log.error(e.getMessage());
            return null;
        }
    }

    @Override
    public WxPayOrderQueryV3Result findByPayOrderId(String transactionId) {
        WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request();
        request.setMchid(merchantId);
        request.setOutTradeNo(transactionId);
        try {
            return wxPayService.queryOrderV3(request);
        } catch (WxPayException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public void cancelTransaction(Long payOrderId) {
        try {
            wxPayService.closeOrderV3(payOrderId.toString());
        } catch (WxPayException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public WxPayRefundV3Result applyRefund(Long payOrderId, Long amount, Long refundAmount, Long refundId, String reason) {
        WxPayRefundV3Request request = new WxPayRefundV3Request();
        request.setOutTradeNo(payOrderId.toString());
        request.setOutRefundNo(refundId.toString());
        request.setReason(reason);
        request.setNotifyUrl(refundCallbackUrl);

        // 金额相关实体
        WxPayRefundV3Request.Amount wxAmount = new WxPayRefundV3Request.Amount();
        wxAmount.setTotal(Integer.parseInt(amount.toString()));
        wxAmount.setRefund(Integer.parseInt(refundAmount.toString()));
        wxAmount.setCurrency(CURRENCY_CNY);
        request.setAmount(wxAmount);

        try {
            return wxPayService.refundV3(request);
        } catch (WxPayException e) {
            log.error(e.getMessage());
            return null;
        }
    }

    @Override
    public WxPayRefundQueryV3Result findByRefundId(Long refundId) {
        try {
            return wxPayService.refundQueryV3(refundId.toString());
        } catch (WxPayException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public void addProfitSharingReceiver(String account, String name, String type, String relationType) {
        ProfitSharingV3Service profitSharingV3Service = wxPayService.getProfitSharingV3Service();
        ProfitSharingReceiver receiver = ProfitSharingReceiver
                .newBuilder()
                .appid(appId)
                .type(type)
                .account(account)
                .name(name)
                .relationType(relationType)
                .build();
        try {
            profitSharingV3Service.addProfitSharingReceiver(receiver);
        } catch (WxPayException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deleteProfitSharingReceiver(String account, String type) {
        ProfitSharingV3Service profitSharingV3Service = wxPayService.getProfitSharingV3Service();
        ProfitSharingReceiver receiver = ProfitSharingReceiver
                .newBuilder()
                .appid(appId)
                .type(type)
                .account(account)
                .build();
        try {
            profitSharingV3Service.deleteProfitSharingReceiver(receiver);
        } catch (WxPayException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public ProfitSharingResult applyProfitsharing(String transactionId, Long profitId, Long amount, String receiverAccount, String receiverName, String receiverType, String profitDescription) {
        ProfitSharingV3Service profitSharingV3Service = wxPayService.getProfitSharingV3Service();
        ProfitSharingRequest request = new ProfitSharingRequest();
        request.setAppid(appId);
        request.setTransactionId(merchantId);
        request.setOutOrderNo(profitId.toString());

        List<ProfitSharingReceiver> receiverList = new ArrayList<>();

        ProfitSharingReceiver receiver = ProfitSharingReceiver
                .newBuilder()
                .appid(appId)
                .type(receiverType)
                .account(receiverAccount)
                .name(receiverName)
                .relationType("PARTNER")
                .description(profitDescription)
                .amount(amount)
                .build();
        receiverList.add(receiver);
        request.setReceivers(receiverList);
        try {
            return profitSharingV3Service.profitSharing(request);
        } catch (WxPayException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }

    }

    @Override
    public ProfitSharingResult findProfitsharing(String transactionId, Long profitId) {
        ProfitSharingV3Service profitSharingV3Service = wxPayService.getProfitSharingV3Service();

        try {
            return profitSharingV3Service.getProfitSharingResult(profitId.toString(), transactionId);
        } catch (WxPayException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }

    }

    @Override
    public WxPayConfig getConfig() {
        return wxPayService.getConfig();
    }
}
